/*
 * can1.c
 *
 *  Created on: Oct 18, 2023
 *      Author: Jinming
 */
#include <string.h>
#include "cmsis_os.h"
#include "can1.h"
#include "log.h"
#include "stm32f4xx_hal_can.h"
#include "task_info.h"

#define TAG		"CAN1"
#define HCAN_HANDLE			hcan1
#define	TX_BUFFER_NUMBER	30

typedef struct
{
	CAN_TxHeaderTypeDef txHeader;
	uint8_t data[8];
}TxBufferVar_t;

typedef struct
{
	TxBufferVar_t buf[TX_BUFFER_NUMBER];
	uint8_t readPos;
	uint8_t writePos;
}TxVar_t;

static CAN_TxHeaderTypeDef   g_tTxHeader;
static CAN_RxHeaderTypeDef   g_tRxHeader;
static uint32_t              g_lTxMailbox;
static CANMsgRx_t			g_aRxMsgBuf[10];
static uint8_t				g_cRxMsgWrite = 0;
static uint8_t 				g_cRxMsgRead = 0;
static TxVar_t				g_tTxVar;

osMutexId_t g_tCan1Mutex = NULL;
const osMutexAttr_t g_tCan1MutexAttr = {
  .name = "Can1"
};

osSemaphoreId_t g_tCAN1TxSem = NULL;
const osSemaphoreAttr_t g_tCAN1TxSemAttr = {
  .name = "CAN1Tx"
};

osSemaphoreId_t g_tCAN1RxSem = NULL;
const osSemaphoreAttr_t g_tCAN1RxSemAttr = {
  .name = "CAN1Rx"
};

osThreadId_t g_tCan1TxTaskHandle = NULL;
const osThreadAttr_t g_tCan1TxTaskAttr = {
  .name = CAN1_TX_TASK_NAME,
  .stack_size = 128 * 8,
  .priority = (osPriority_t) CAN1_TX_TASK_PRIO,
};

static int (*Can1RxNotify)(void) = NULL;

void CAN1_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan)
{
	CANMsgRx_t *pRxMsg = &g_aRxMsgBuf[g_cRxMsgWrite];
	g_tRxHeader.StdId = 0xFFFFFFFF;
	g_tRxHeader.ExtId = 0xFFFFFFFF;;
	/* Get RX message */
	if (HAL_CAN_GetRxMessage(hcan, CAN_RX_FIFO0, &g_tRxHeader, pRxMsg->data) != HAL_OK)
	{
		/* Reception Error */
		LOGE(TAG, "Can1 get msg error!");
		return;
	}
	pRxMsg->id = g_tRxHeader.StdId;
	pRxMsg->extId = g_tRxHeader.ExtId;
	pRxMsg->len = g_tRxHeader.DLC;

//	LOGD(TAG, "write pos=%d", g_cRxMsgWrite);
//	LOGD(TAG, "id:%x, len=%d, %x %x %x %x", pRxMsg->id, pRxMsg->len, pRxMsg->data[0], pRxMsg->data[1], pRxMsg->data[2], pRxMsg->data[3]);

	VALUE_INC(g_cRxMsgWrite, sizeof(g_aRxMsgBuf)/sizeof(g_aRxMsgBuf[0]));
	if(g_cRxMsgWrite == g_cRxMsgRead)
	{
		VALUE_INC(g_cRxMsgRead, sizeof(g_aRxMsgBuf)/sizeof(g_aRxMsgBuf[0]));
		LOGE(TAG, "CAN1 Rx buf is full!!!");
	}

	osSemaphoreRelease(g_tCAN1RxSem);

	if(Can1RxNotify)
	{
		if(Can1RxNotify())
		{
			LOGE(TAG, "CAN1 notify fail!!!");
		}
	}
}

void CAN1_tx_complete_callback(CAN_HandleTypeDef *hcan)
{
	osSemaphoreRelease(g_tCAN1TxSem);
}

void CAN1_tx_task(void *param)
{
	osStatus_t status;

	while(1)
	{
		status = osSemaphoreAcquire(g_tCAN1TxSem, portMAX_DELAY);
		if(status)
		{
			LOGD(TAG, "CAN1 tx sem acquire fail");
			continue;
		}

		if(g_tTxVar.readPos == g_tTxVar.writePos)		//发送缓冲区为空
		{
			continue;
		}

		if(HAL_CAN_GetTxMailboxesFreeLevel(&HCAN_HANDLE) == 0)		//没有空闲邮箱
		{
			continue;
		}

		if (HAL_CAN_AddTxMessage(&HCAN_HANDLE, &g_tTxVar.buf[g_tTxVar.readPos].txHeader, g_tTxVar.buf[g_tTxVar.readPos].data, &g_lTxMailbox) != HAL_OK)
		{
			LOGE(TAG, "CAN1 tx error");
			continue;
		}
		VALUE_INC(g_tTxVar.readPos, TX_BUFFER_NUMBER);
	}
}

int can1_config(int (*func)(void))
{
  CAN_FilterTypeDef  sFilterConfig;

  /*##-2- Configure the CAN Filter ###########################################*/
  sFilterConfig.FilterBank = 0;
  sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK;
  sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT;
  sFilterConfig.FilterIdHigh = 0x0000;
  sFilterConfig.FilterIdLow = 0x0000;
  sFilterConfig.FilterMaskIdHigh = 0x0000;
  sFilterConfig.FilterMaskIdLow = 0x0000;
  sFilterConfig.FilterFIFOAssignment = CAN_RX_FIFO0;
  sFilterConfig.FilterActivation = ENABLE;
  sFilterConfig.SlaveStartFilterBank = 14;

  if (HAL_CAN_ConfigFilter(&HCAN_HANDLE, &sFilterConfig) != HAL_OK)
  {
    /* Filter configuration Error */
	  LOGE(TAG, "CAN1 config filter error");
    return -1;
  }

  /*##-3- Start the CAN peripheral ###########################################*/
  if (HAL_CAN_Start(&HCAN_HANDLE) != HAL_OK)
  {
    /* Start Error */
	  LOGE(TAG, "CAN1 start error");
    return -1;
  }

  /*##-4- Activate CAN RX notification #######################################*/
  if (HAL_CAN_ActivateNotification(&HCAN_HANDLE, CAN_IT_RX_FIFO0_MSG_PENDING) != HAL_OK)
  {
    /* Notification Error */
	  LOGE(TAG, "CAN1 notiry error");
    return -1;
  }

  if (HAL_CAN_ActivateNotification(&HCAN_HANDLE, CAN_IT_TX_MAILBOX_EMPTY) != HAL_OK)
  {
	  /* Notification Error */
	  LOGE(TAG, "CAN1 notiry error");
	  return -1;
  }

//  HAL_CAN_RegisterCallback(&HCAN_HANDLE, HAL_CAN_RX_FIFO0_MSG_PENDING_CB_ID, CAN1_RxFifo0MsgPendingCallback);
//  HAL_CAN_RegisterCallback(&HCAN_HANDLE, HAL_CAN_TX_MAILBOX0_COMPLETE_CB_ID, CAN1_tx_complete_callback);
//  HAL_CAN_RegisterCallback(&HCAN_HANDLE, HAL_CAN_TX_MAILBOX1_COMPLETE_CB_ID, CAN1_tx_complete_callback);
//  HAL_CAN_RegisterCallback(&HCAN_HANDLE, HAL_CAN_TX_MAILBOX2_COMPLETE_CB_ID, CAN1_tx_complete_callback);

  if(g_tCan1Mutex == NULL)
  {
	  g_tCan1Mutex = osMutexNew(&g_tCan1MutexAttr);
	  if(g_tCan1Mutex == NULL)
	  {
		  LOGE(TAG, "CAN1 mutex create error");
	  }
  }
  Can1RxNotify = func;

  if(g_tCAN1TxSem == NULL)
  {
	  g_tCAN1TxSem = osSemaphoreNew(6, 0, &g_tCAN1TxSemAttr);
	  if(g_tCAN1TxSem == NULL)
	  {
		LOGE(TAG, "CAN1 tx sem create error!!!");
	  	return -1;
	  }
  }

  	if(g_tCAN1RxSem == NULL)
  	{
		g_tCAN1RxSem = osSemaphoreNew(3, 0, &g_tCAN1RxSemAttr);
		if(g_tCAN1RxSem == NULL)
		{
			LOGE(TAG, "CAN2 rx sem create error!!!");
			return -1;
		}
  	}

  	if(g_tCan1TxTaskHandle == NULL)
  	{
		g_tCan1TxTaskHandle = osThreadNew(CAN1_tx_task, NULL, &g_tCan1TxTaskAttr);
		if(g_tCan1TxTaskHandle == NULL)
		{
			LOGE(TAG, "CAN1 tx task create error!!!");
			return -1;
		}
  	}

  g_tTxVar.readPos = 0;
  g_tTxVar.writePos = 0;

  /*##-5- Configure Transmission process #####################################*/
  g_tTxHeader.StdId = 0x321;
  g_tTxHeader.ExtId = 0x01;
  g_tTxHeader.RTR = CAN_RTR_DATA;
  g_tTxHeader.IDE = CAN_ID_EXT;
  g_tTxHeader.DLC = 2;
  g_tTxHeader.TransmitGlobalTime = DISABLE;

  return 0;
}

void can1_unconfig(void)
{
	if(HAL_CAN_DeactivateNotification(&HCAN_HANDLE, CAN_IT_TX_MAILBOX_EMPTY) != HAL_OK)
	{
		LOGE(TAG, "can1 delete tx notiry error");
	}

	if(HAL_CAN_DeactivateNotification(&HCAN_HANDLE, CAN_IT_RX_FIFO0_MSG_PENDING) != HAL_OK)
	{
		LOGE(TAG, "can1 delete rx notiry error");
	}

	if(HAL_CAN_Stop(&HCAN_HANDLE) != HAL_OK)
	{
		LOGE(TAG, "can1 stop error");
	}
}

int can1_ext_write(uint32_t id, uint8_t *pData, uint8_t len)
{
	osStatus_t osStatus;
	CAN_TxHeaderTypeDef *txHeader;
	if(len == 0)
		return -1;

	osStatus = osMutexAcquire(g_tCan1Mutex, 10);
	if(osStatus)
	{
		return osStatus;
	}

	if((g_tTxVar.readPos == g_tTxVar.writePos) && (HAL_CAN_GetTxMailboxesFreeLevel(&HCAN_HANDLE) != 0))  //缓冲已空，邮箱也空闲
	{
		g_tTxHeader.StdId = 0x321;
		g_tTxHeader.ExtId = id;
		g_tTxHeader.RTR = CAN_RTR_DATA;
		g_tTxHeader.IDE = CAN_ID_EXT;
		g_tTxHeader.DLC = (len > 8) ? 8 : len;
		g_tTxHeader.TransmitGlobalTime = DISABLE;

		if (HAL_CAN_AddTxMessage(&HCAN_HANDLE, &g_tTxHeader, pData, &g_lTxMailbox) != HAL_OK)
		{
			LOGE(TAG, "Can1 tx error");
			osMutexRelease(g_tCan1Mutex);
			return -1;
		}
	}
	else
	{
		if((g_tTxVar.readPos - g_tTxVar.writePos == 1) || (g_tTxVar.readPos == 0 && g_tTxVar.writePos == TX_BUFFER_NUMBER))  //缓冲区已满
		{
//			LOGE(TAG, "CAN1 tx buffer is full!!!");
			return osMutexRelease(g_tCan1Mutex);
		}

		txHeader = &g_tTxVar.buf[g_tTxVar.writePos].txHeader;

		txHeader->StdId = 0x321;
		txHeader->ExtId = id;
		txHeader->RTR = CAN_RTR_DATA;
		txHeader->IDE = CAN_ID_EXT;
		txHeader->DLC = (len > 8) ? 8 : len;
		txHeader->TransmitGlobalTime = DISABLE;
		memcpy(g_tTxVar.buf[g_tTxVar.writePos].data, pData, (len > 8) ? 8 : len);
		VALUE_INC(g_tTxVar.writePos, TX_BUFFER_NUMBER);
	}

	osMutexRelease(g_tCan1Mutex);
	return 0;
}

int can1_std_write(uint32_t id, uint8_t *pData, uint8_t len)
{
	osStatus_t osStatus;
	CAN_TxHeaderTypeDef *txHeader;
	if(len == 0)
		return -1;

	osStatus = osMutexAcquire(g_tCan1Mutex, 10);
	if(osStatus)
	{
		return osStatus;
	}

	if((g_tTxVar.readPos == g_tTxVar.writePos) && (HAL_CAN_GetTxMailboxesFreeLevel(&HCAN_HANDLE) != 0))  //缓冲已空，邮箱也空闲
	{
		g_tTxHeader.StdId = id;
		g_tTxHeader.ExtId = 0;
		g_tTxHeader.RTR = CAN_RTR_DATA;
		g_tTxHeader.IDE = CAN_ID_STD;
		g_tTxHeader.DLC = (len > 8) ? 8 : len;
		g_tTxHeader.TransmitGlobalTime = DISABLE;

		if (HAL_CAN_AddTxMessage(&HCAN_HANDLE, &g_tTxHeader, pData, &g_lTxMailbox) != HAL_OK)
		{
			LOGE(TAG, "Can1 tx error");
			osMutexRelease(g_tCan1Mutex);
			return -1;
		}
	}
	else
	{
		if((g_tTxVar.readPos - g_tTxVar.writePos == 1) || (g_tTxVar.readPos == 0 && g_tTxVar.writePos == TX_BUFFER_NUMBER))  //缓冲区已满
		{
			LOGE(TAG, "CAN1 tx buffer is full!!!");
			return osMutexRelease(g_tCan1Mutex);
		}

		txHeader = &g_tTxVar.buf[g_tTxVar.writePos].txHeader;

		txHeader->StdId = id;
		txHeader->ExtId = 0;
		txHeader->RTR = CAN_RTR_DATA;
		txHeader->IDE = CAN_ID_STD;
		txHeader->DLC = (len > 8) ? 8 : len;
		txHeader->TransmitGlobalTime = DISABLE;
		memcpy(g_tTxVar.buf[g_tTxVar.writePos].data, pData, (len > 8) ? 8 : len);
		VALUE_INC(g_tTxVar.writePos, TX_BUFFER_NUMBER);
	}

	osMutexRelease(g_tCan1Mutex);
	return 0;
}

int can1_read(CANMsgRx_t *msg, uint32_t timeout)
{
	osStatus_t status;

	status = osSemaphoreAcquire(g_tCAN1RxSem, timeout);
	if(status)
	{
//		LOGE(TAG, "CAN1 Rx sem acquire fail");
		return -1;
	}

	if(g_cRxMsgWrite == g_cRxMsgRead)
	{
		return -1;
	}

	memcpy(msg, &g_aRxMsgBuf[g_cRxMsgRead], sizeof(CANMsgRx_t));
//	LOGD(TAG, "id:%x, len=%d, %x %x %x %x", msg->id, msg->len, msg->data[0], msg->data[1], msg->data[2], msg->data[3]);
	VALUE_INC(g_cRxMsgRead, sizeof(g_aRxMsgBuf)/sizeof(g_aRxMsgBuf[0]));

	return 0;
}

void can1_rx_clear(void)
{
	uint32_t count = osSemaphoreGetCount(g_tCAN1RxSem);
	if(count)
	{
		for(uint32_t i = 0; i < count; i++)
		{
			osSemaphoreAcquire(g_tCAN1RxSem, 0);
		}
	}
	g_cRxMsgWrite = 0;
	g_cRxMsgRead = 0;
}
